﻿using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using System.Text.RegularExpressions;

namespace PpSmsSender
{
    public interface IPhoneNumber
    {
        PhoneNumber.NumberCategory Category { get; }
        string NormalizePhone(string number);
        string[] DeNormalizedPhoneNumber();
    }

    [ComplexType]
    public class PhoneNumber : IPhoneNumber
    {
        public enum NumberCategory
        {
            Unknown = 0,
            Mobile = 1,
            Standard = 2
        }

        public static Type FactoryPhoneNumberType = typeof(PhoneNumber);
        public static PhoneNumber CreateLocal(string number)
        {
            try
            {
                return (PhoneNumber)FactoryPhoneNumberType
                               .GetConstructor(
                                   BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.Instance,
                                   null,
                                   new Type[] { typeof(string) },
                                   null
                               )
                               .Invoke(new object[] { number });
            }
            catch
            {
                return null;
            }
        }

        public static PhoneNumber CreateLocal()
        {
            try
            {
                ConstructorInfo constructorInfo = FactoryPhoneNumberType.GetConstructor(
                                                                        BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.Instance,
                                                                        null,
                                                                        new Type[] { },
                                                                        null);
                return (PhoneNumber)constructorInfo.Invoke(new object[] { });
            }
            catch
            {
                return null;
            }
        }


        private string _number = "";

        public PhoneNumber()
        {
        }
        public PhoneNumber(string number)
        {
            this.Number = number;
        }

        public bool IsEmpty()
        {
            return this.Number == "";
        }

        public PhoneNumber(PhoneNumber number)
        {
            this.Number = number.Number;
        }

        public static implicit operator string(PhoneNumber phoneNumber)
        {
            return phoneNumber.Number;
        }

        public static implicit operator PhoneNumber(string phoneNumber)
        {
            PhoneNumber newNumber = CreateLocal();
            newNumber.Number = phoneNumber;
            return newNumber;
        }

        public static bool operator ==(PhoneNumber c1, PhoneNumber c2)
        {
            if (((object)c1) == null && ((object)c2) == null)
                return true;
            if (((object)c1) == null || ((object)c2) == null)
                return false;

            string phoneNumber1 = c1.Number;
            string phoneNumber2 = c2.Number;
            return phoneNumber1 == phoneNumber2;
        }

        public static bool operator !=(PhoneNumber c1, PhoneNumber c2)
        {
            return !(c1 == c2);
        }



        public override string ToString()
        {
            return this.Number;
        }

        public virtual NumberCategory Category
        {
            get { return NumberCategory.Unknown; }
        }

        public virtual bool IsMobile
        {
            get { return this.Category == NumberCategory.Mobile; }
        }

        public string Number
        {
            get { return _number; }
            set { _number = NormalizePhone(value); }
        }

        // A phone number should be in the format: 
        //   +<countrycode><number without leading 0>

        public virtual string NormalizePhone(string number)
        {
            if (number + "" == "")
                return "";
            string phoneNumber = number;
            Regex remove = new Regex(@"[^0-9+]");
            phoneNumber = remove.Replace(phoneNumber, "");

            return phoneNumber;
        }

        public virtual string[] DeNormalizedPhoneNumber()
        {
            string[] phoneNumbers = new string[3];
            string phoneNumber = Number;
            phoneNumbers[0] = phoneNumber;

            return phoneNumbers;
        }
    }
}
